526F - Pudding Monsters - CodeForces Solution


data structures divide and conquer *3000

Please click on ads to support us..

C++ Code:

#include <bits/stdc++.h>
using namespace std;

#define ssize(x) (int)(x).size()

template <class T, class F> struct RMQ {
    vector<vector<T>> dp;
    F op;
    RMQ() {}
    RMQ(const vector<T>& a, F a_op) : dp(1, a), op(a_op) {
        for (int i = 0; (2 << i) <= ssize(a); i++) {
            dp.emplace_back(ssize(a) - (2 << i) + 1);
            transform(begin(dp[i]), end(dp[i]) - (1 << i), begin(dp[i]) + (1 << i), begin(dp[i + 1]), op);
        }
    }
    inline T query(int le, int ri) {
        assert(0 <= le && le < ri && ri <= ssize(dp[0]));
        int lg = __lg(ri - le);
        return op(dp[lg][le], dp[lg][ri - (1 << lg)]);
    }
};

struct perm_tree {
    vector<bool> is_join;
    vector<int> mn_idx, mn_val, len;
    int root;
    vector<vector<int>> adj;
    bool touches(int u, int v) {
        return mn_val[u] == mn_val[v] + len[v] || mn_val[v] == mn_val[u] + len[u];
    }
    int allocate(bool join, int mn_i, int mn_v, int ln, const vector<int>& ch) {
        int u = ssize(adj);
        is_join.push_back(join);
        mn_idx.push_back(mn_i);
        mn_val.push_back(mn_v);
        len.push_back(ln);
        adj.push_back(ch);
        return u;
    }
    perm_tree(const vector<int>& a) {
        int n = ssize(a);
        vector<int> mn_i(n), mx_i(n);
        {
            vector<int> a_inv(n, -1);
            for (int i = 0; i < n; i++) {
                assert(0 <= a[i] && a[i] < n && a_inv[a[i]] == -1);
                a_inv[a[i]] = i;
            }
            RMQ min_idx(a_inv, [](int x, int y) {return min(x, y);});
            RMQ max_idx(a_inv, [](int x, int y) {return max(x, y);});
            for (int i = 1; i < n; i++) {
                auto [le, ri] = minmax(a[i - 1], a[i]);
                mn_i[i] = min_idx.query(le, ri + 1);
                mx_i[i] = max_idx.query(le, ri + 1);
            }
        }
        RMQ min_value(a, [](int x, int y) {return min(x, y);});
        for (int i = 0; i < n; i++) allocate(1, i, a[i], 1, {});
        vector<int> st;
        vector<array<int, 3>> fail;
        for (int i = 0; i < n; i++) {
            int u = i;
            while (!empty(st)) {
                int v = st.back();
                if (is_join[v] && !empty(adj[v]) && touches(adj[v].back(), u)) {
                    mn_idx[v] = min(mn_idx[v], mn_idx[u]);
                    mn_val[v] = min(mn_val[v], mn_val[u]);
                    len[v] += len[u];
                    adj[v].push_back(u);
                    u = v;
                    st.pop_back();
                    continue;
                }
                if (touches(u, v)) {
                    assert(mn_idx[v] < mn_idx[u]);
                    assert(mn_idx[v] + len[v] == mn_idx[u]);
                    u = allocate(1, mn_idx[v], min(mn_val[u], mn_val[v]), len[u] + len[v], {v, u});
                    st.pop_back();
                    continue;
                }
                int idx = ssize(st) - 1;
                assert(mn_idx[v] < mn_idx[u]);
                assert(mn_idx[v] + len[v] == mn_idx[u]);
                int le = min(mn_idx[v], mn_i[mn_idx[u]]);
                assert(mn_idx[u] + len[u] - 1 == i);
                int ri = max(i, mx_i[mn_idx[u]]);
                assert(ri - le + 1 > len[u] + len[v]);//initially there's some gap between them, else we'd have hit case 2
                assert(!empty(st));
                while(!empty(fail) && fail.back()[0] >= idx) fail.pop_back();
                while (ri == i && le != mn_idx[st[idx]]) {
                    assert(!empty(fail));
                    assert(fail.back()[0] < idx);
                    idx = fail.back()[0];
                    le = min(le, fail.back()[1]);
                    ri = max(ri, fail.back()[2]);
                    fail.pop_back();
                }
                if (ri > i) {
                    assert(!empty(st));
                    fail.push_back({idx, le, ri});
                    break;
                }
                st.push_back(u);
                u = allocate(0, le, min_value.query(le, ri + 1), ri - le + 1, {begin(st) + idx, end(st)});
                st.resize(idx);
            }
            st.push_back(u);
        }
        assert(ssize(st) == 1);
        root = st[0];
    }
};

int main() {
    cin.tie(0)->sync_with_stdio(0);

    int n;
    cin >> n;
    vector<int> a(n);
    for(int i = 0; i < n; i++) {
        int r, c;
        cin >> r >> c;
        r--,c--;
        a[r] = c;
    }
    perm_tree pt(a);
    queue<int> q;
    q.push(pt.root);
    long long res = 0;
    while(!empty(q)) {
        int u = q.front();
        q.pop();
        //cout << "range: " << pt.mn_val[u] << " " << pt.mn_val[u] + pt.len[u] - 1 << " join: " << pt.is_join[u] << " num childs: " << ssize(pt.adj[u]) << endl;
        if(empty(pt.adj[u])) res++;
        else if(pt.is_join[u]) res += 1LL * ssize(pt.adj[u]) * (ssize(pt.adj[u]) - 1) / 2;
        else res++;
        for(int v : pt.adj[u]) q.push(v);
    }
    cout << res << '\n';
    return 0;
}


Comments

Submit
0 Comments
More Questions

145. Binary Tree Postorder Traversal
94. Binary Tree Inorder Traversal
101. Symmetric Tree
77. Combinations
46. Permutations
226. Invert Binary Tree
112. Path Sum
1556A - A Variety of Operations
136. Single Number
169. Majority Element
119. Pascal's Triangle II
409. Longest Palindrome
1574A - Regular Bracket Sequences
1574B - Combinatorics Homework
1567A - Domino Disaster
1593A - Elections
1607A - Linear Keyboard
EQUALCOIN Equal Coins
XOREQN Xor Equation
MAKEPAL Weird Palindrome Making
HILLSEQ Hill Sequence
MAXBRIDGE Maximise the bridges
WLDRPL Wildcard Replacement
1221. Split a String in Balanced Strings
1002. Find Common Characters
1602A - Two Subsequences
1555A - PizzaForces
1607B - Odd Grasshopper
1084A - The Fair Nut and Elevator
1440B - Sum of Medians